package hasthi.tools;

import hasthi.common.BaseContext;
import hasthi.common.HasthiException;
import hasthi.common.Utils;
import hasthi.common.HasthiException.FaultCode;
import hasthi.common.constants.HasthiConstants;
import hasthi.container.ContainerUtils;
import hasthi.container.SimpleMessageContext;
import hasthi.container.UnicastContianier;
import hasthi.instrument.HostAgent;
import hasthi.manager.ExecuteCommandDocument;
import hasthi.manager.ExecuteCommandResponseDocument;
import hasthi.manager.ExecuteCommandDocument.ExecuteCommand;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.w3c.dom.Element;

public class TomcatUtils {
    protected static Log log = LogFactory.getLog(HasthiConstants.LOGGER_NAME);
    public static File findTomcatHome(){
        String tomcatHome = System.getProperty("catalina.home");
        if(tomcatHome == null){
            tomcatHome = System.getenv("CATALINA_HOME");
        }
        
        if(tomcatHome != null && new File(tomcatHome,"conf/server.xml").exists()){
            return new File(tomcatHome);
        }
        return null;
    }
    
    
    public static String findTomcatEndpoint(File tomcatHome) throws HasthiException{
        String httpPort = null;
        String httpsPort = null;
        try {
            File serverConfigFle = new File(tomcatHome,"conf/server.xml");
            if(serverConfigFle.exists()){
                XmlObject tomcatConfig = XmlObject.Factory.parse(serverConfigFle);
                
                XmlObject[] connectors = tomcatConfig.selectPath("$this//Connector");
                if(connectors != null){
                    for(XmlObject connector:connectors){
                        Element node = ((Element)connector.getDomNode()); 
                        String port = node.getAttribute("port");
                        String scheme = node.getAttribute("scheme");
                        String protocol = node.getAttribute("protocol");
                        if(scheme.equals("https")){
                            httpsPort = port;
                        }else if(protocol == null|| protocol.trim().length() ==0 
                                || protocol.contains("HTTP") || protocol.contains("http")){
                            httpPort = port;
                        }
                    }
                }
                if(httpsPort != null){
                    return new StringBuffer().append("https://").append(Utils.getLocalHost())
                        .append(":").append(httpsPort).append("/").toString();
                }else{
                    return new StringBuffer().append("http://").append(Utils.getLocalHost())
                    .append(":").append(httpPort).append("/").toString();
                }
            }
            return null;
        } catch (XmlException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        } catch (IOException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        }
     }
    
    
    public static void shutDownTomcat(String tomcatHome,BaseContext baseContext) throws HasthiException{
        try {
            if(!new File(tomcatHome,"conf/server.xml").exists()){
                throw new HasthiException("Given dir is not a tomcat Home",FaultCode.InvaliedLocalArgumnet);
            }
            log.info("Shutting down tomcat @"+tomcatHome);
            File serverConfigFle = new File(tomcatHome,"conf/server.xml");
            if(serverConfigFle.exists()){
                XmlObject tomcatConfig = XmlObject.Factory.parse(serverConfigFle);
                
                XmlObject[] connectors = tomcatConfig.selectPath("$this//Server");
                String port = null;
                String shutdownCmd = null;
                
                if(connectors != null){
                    for(XmlObject connector:connectors){
                        Element node = ((Element)connector.getDomNode()); 
                        port = node.getAttribute("port");
                        shutdownCmd = node.getAttribute("shutdown");
                    }
                }
                if(port == null || shutdownCmd == null){
                    throw new HasthiException("Cannot find shutdown information from Tomcat@"+tomcatHome,FaultCode.ConfigError);
                }else{
                    Socket socket = new Socket("127.0.0.1", Integer.parseInt(port));
                    if (socket.isConnected()) {
                        PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
                        pw.println(shutdownCmd);//send shut down command
                        
//                        InputStream in = socket.getInputStream();
                        
//                        byte[] data = new byte[in.available()];
//                        in.read(data);
//                        
//                        System.out.println(new String(data));
                        pw.close();
                        socket.close();
                    }
                    
                    Thread.sleep(2000);
                    try {
                        ContainerUtils.doUrlGet(baseContext, findTomcatEndpoint(new File(tomcatHome)));
                    } catch (Exception e) {
                        return;
                    }
                    throw new HasthiException("Tomcat shutdown failed for "+tomcatHome,FaultCode.ConfigError);
                }
            }
        } catch (NumberFormatException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        } catch (UnknownHostException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        } catch (XmlException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        } catch (IOException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        } catch (InterruptedException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        }
    }
    
    public static ExecuteCommandResponseDocument startTomcat(String tomcatHome,HostAgent hostAgent,BaseContext 
            baseContext) throws HasthiException{
        try {
            File tomcatHomeDir = new File(tomcatHome);
            if(!new File(tomcatHome,"conf/server.xml").exists()){
                throw new HasthiException("Given dir is not a tomcat Home",FaultCode.InvaliedLocalArgumnet);
            }
            String[] nnv = new String[]{"CATALINA_HOME="+tomcatHome};
            ExecuteCommandResponseDocument response = hostAgent.runJob(tomcatHome+"/bin/startup.sh", nnv, tomcatHome+"/bin", "");
            Thread.sleep(5000);
            
            String tomcatEndpoint = findTomcatEndpoint(tomcatHomeDir);
            
            try {
                ContainerUtils.doUrlGet(baseContext, tomcatEndpoint);
            } catch (HasthiException e) {
                throw new HasthiException("Error "+ e.getMessage() + " stdout of startup was "+ response.getExecuteCommandResponse().getStdouterr(),
                        e,FaultCode.InstrumentationError);
            }
            response.getExecuteCommandResponse().addNewResponseParams().setStringValue(tomcatEndpoint);
            return response;
        } catch (InterruptedException e) {
            throw new HasthiException(e,FaultCode.LocalError);
        }
    }
    
   
    
    
    public static void main(String[] args) throws HasthiException {
        //System.out.println(TomcatUtils.findTomcatEndpoint(new File("/u/hperera/tools/apache-tomcat-5.5.17")));
        BaseContext baseContext = new BaseContext();
        TomcatUtils.shutDownTomcat("/u/hperera/tools/apache-tomcat-5.5.17", baseContext);
        //HostAgent hostAgent = new HostAgent(baseContext);
        //TomcatUtils.startTomcat("/u/hperera/tools/apache-tomcat-5.5.17", hostAgent,baseContext);
    }
    
    
}
